﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MockupDesigner.AppItems.Documents;

namespace MockupDesigner.AppItems.Commands
{
    public class CommandProcessor
    {
        private static int capacity = 40;
        private IList<ICommand> stack;
        private int currentIndex;

        public CommandProcessor()
        {
            stack = new List<ICommand>();
        }

        public bool IsCanceling { get; set; }
        public bool IsRedoing { get; set; }
        public bool IsExecuting { get; set; }

        public bool Undo_Enabled
        {
            get { return stack.Count > 0 && currentIndex < stack.Count; }
        }

        public bool Redo_Enabled
        {
            get
            {
                return currentIndex > 0;
            }
        }

        /// <summary>
        /// Execute a ICommand
        /// </summary>
        /// <param name="command">the Command to execute</param>
        /// <param name="target">the target of the Command</param>
        /// <param name="parameters">the parameters of the Command</param>
        public void ExecuteCommand(ICommand command, object target, params object[] parameters)
        {
            IsExecuting = true;
            command.Execute(target, parameters);

            switch (command.CommandType)
            {
                case CommandType.Irreversible: // we clear the history
                    this.currentIndex = 0;
                    this.stack.Clear();
                    break;
                case CommandType.Undoable: // we register the command
                    if (this.stack.Count == capacity)
                    {
                        this.stack.RemoveAt(0);
                    }
                    // When we execute a command, we must verify the current position
                    // if position > 0, we delete every commands found after this position and add the new command at the end
                    if (this.currentIndex > 0)
                    {
                        for (int i = 0; i < this.currentIndex; i++)
                        {
                            if (this.stack.Count > 0)
                                this.stack.RemoveAt(this.stack.Count - 1);
                        }
                        this.currentIndex = 0;
                    }
                    this.stack.Add(command);
                    if (target is DesignerCanvas)
                    {
                        ((Document)((System.Windows.FrameworkElement)System.Windows.Media.VisualTreeHelper.GetParent((DesignerCanvas)target)).DataContext).IsSaved = false;
                    }

                    break;
                default:
                    break;
            }
            IsExecuting = false;
        }

        /// <summary>
        /// The CommandProcessor must execute the command found at the previous position in the stack
        /// </summary>
        public void Undo()
        {
            if (stack.Count == 0)
                return;
            IsCanceling = true;
            ICommand command = stack[stack.Count - currentIndex - 1]; // take the last command
            this.currentIndex += 1;
            if (currentIndex > stack.Count)
            {
                currentIndex = stack.Count;
            }
            command.Undo();
            IsCanceling = false;
        }

        /// <summary>
        /// The CommandProcessor must execute the command found at the next position in the stack
        /// </summary>
        public void Redo()
        {
            if (this.currentIndex == 0)
                return;
            IsRedoing = true;
            ICommand command = stack[stack.Count - this.currentIndex]; // take the next command
            if (this.currentIndex > 0)
            {
                this.currentIndex -= 1;
            }
            command.Redo();
            IsRedoing = false;
        }

    }
}
